package org.example.myframework.frame.common.redis.utils;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Component
@Slf4j
public class CacheUtil<K, V> {

    // 是否走缓存
    @Value("${guava.cache.switch}")
    public Boolean switchCache;

    // 初始化本地缓存
    private Cache<String, String > localCache = CacheBuilder.newBuilder()
            .maximumSize(5000)
            // 过期之后进行写操作，无法动态配置。类加载时，guava就已经初始化
            .expireAfterWrite(3, TimeUnit.SECONDS)
            .build();

    /**
     *
     * @param skuIdList 查询条件
     * @param cachePrefix 缓存前缀
     * @param clazz 返回需要封装的实体类类型
     * @param function 函数编程方法
     * @return
     */
    public Map<K, V> getResult(List<K> skuIdList, String cachePrefix, Class<V> clazz, Function<List<K>,Map<K, V>> function) {

        if (CollectionUtils.isEmpty(skuIdList)) {
            return Collections.emptyMap();
        }
        Map<K, V> resultMap = new HashMap<K, V>(16);
        if (!switchCache) {
            resultMap = function.apply(skuIdList);
            return resultMap;
        }
        List<K> noCacheIdList = new ArrayList<>();
        for (K id : skuIdList) {
            String cacheKey = cachePrefix + "_" + id;
            String content = localCache.getIfPresent(cacheKey);
            if (StringUtils.isNotBlank(content)) {
                // 如果能从缓存中拿到值，则将值转换成对应class的对象
                V v = JSON.parseObject(content, clazz);
                resultMap.put(id, v);
            } else {
                noCacheIdList.add(id);
            }
        }
        if (CollectionUtils.isEmpty(noCacheIdList)) {
            return resultMap;
        }

        Map<K, V> noCacheResultMap = function.apply(noCacheIdList);
        if (CollectionUtils.isEmpty(noCacheResultMap)) {
            return resultMap;
        }

        for (Map.Entry<K, V> entry : noCacheResultMap.entrySet()) {
            K id = entry.getKey();
            V result = entry.getValue();
            resultMap.put(id, result);
            String cacheKey = cachePrefix + "_" + id;
            // 序列化成String push
            localCache.put(cacheKey, JSON.toJSONString(result));
        }
        return resultMap;
    }

}
























